package Util;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.io.StringReader;
import java.util.HashMap;
import java.util.Map;

/**
 * 简易XML响应体解析工具类
 * 适用于结构简单的XML数据解析，专注于常用的节点文本和属性获取
 */
public class SimpleXmlParser {
    // 初始化文档构建工厂，禁用外部实体防止安全漏洞
    private static final DocumentBuilderFactory factory;

    static {
        factory = DocumentBuilderFactory.newInstance();
        try {
            // 安全配置：防止XXE攻击
            factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
        } catch (ParserConfigurationException e) {
            throw new RuntimeException("XML解析器初始化失败", e);
        }
    }

    /**
     * 从XML字符串解析出根节点
     * @param xmlStr XML响应体字符串
     * @return 根元素节点
     * @throws ParserConfigurationException 解析器配置异常
     * @throws IOException IO异常
     * @throws SAXException SAX解析异常
     */
    public static Element parseRootElement(String xmlStr)
            throws ParserConfigurationException, IOException, SAXException {
        if (xmlStr == null || xmlStr.trim().isEmpty()) {
            throw new IllegalArgumentException("XML字符串不能为空");
        }

        DocumentBuilder builder = factory.newDocumentBuilder();
        Document doc = builder.parse(new InputSource(new StringReader(xmlStr)));
        return doc.getDocumentElement();
    }

    /**
     * 获取指定节点下的直接子节点文本值
     * @param parent 父节点
     * @param tagName 子节点标签名
     * @return 节点文本值，不存在则返回空字符串
     */
    public static String getChildText(Element parent, String tagName) {
        if (parent == null || tagName == null) {
            return "";
        }

        NodeList nodeList = parent.getElementsByTagName(tagName);
        if (nodeList.getLength() > 0) {
            Node node = nodeList.item(0);
            return node.getTextContent().trim();
        }
        return "";
    }

    /**
     * 获取节点的属性值
     * @param element 节点
     * @param attrName 属性名
     * @return 属性值，不存在则返回空字符串
     */
    public static String getAttribute(Element element, String attrName) {
        if (element == null || attrName == null) {
            return "";
        }
        String value = element.getAttribute(attrName);
        return value != null ? value.trim() : "";
    }

    /**
     * 将简单XML结构转换为Map键值对
     * 适用于单层节点结构：<root><a>1</a><b>2</b></root>
     * @param xmlStr XML字符串
     * @return 节点名-文本值的Map
     * @throws Exception 解析异常
     */
    public static Map<String, String> toMap(String xmlStr) throws Exception {
        Map<String, String> resultMap = new HashMap<>();
        Element root = parseRootElement(xmlStr);

        NodeList childNodes = root.getChildNodes();
        for (int i = 0; i < childNodes.getLength(); i++) {
            Node node = childNodes.item(i);
            // 只处理元素节点
            if (node.getNodeType() == Node.ELEMENT_NODE) {
                resultMap.put(node.getNodeName(), node.getTextContent().trim());
            }
        }
        return resultMap;
    }

    /**
     * 快速获取XML中的某个节点值（简化版）
     * @param xmlStr XML字符串
     * @param tagName 要获取的节点名
     * @return 节点文本值
     */
    public static String getValue(String xmlStr, String tagName) {
        try {
            Element root = parseRootElement(xmlStr);
            return getChildText(root, tagName);
        } catch (Exception e) {
            System.err.println("解析XML节点[" + tagName + "]失败: " + e.getMessage());
            return "";
        }
    }
}
